﻿Imports System.Text.RegularExpressions
Imports System.ComponentModel
Imports System.IO

Public Enum RegexSearchMode
    SampleInput
    FindInFiles
End Enum

Public Class MainWindow
    Implements INotifyPropertyChanged

#Region "Events"
    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
#End Region

#Region "Properties"

    Private ReadOnly _executeRegex As New ExecuteRegExCommand(Me)
    Public ReadOnly Property ExecuteRegex() As ICommand
        Get
            Return _executeRegex
        End Get
    End Property

    Private ReadOnly _browse As New FindInFilesBrowseFoldersCommand(Me)
    Public ReadOnly Property Browse As ICommand
        Get
            Return _browse
        End Get
    End Property

    Private ReadOnly _saveFile As New SaveFileCommand(Me)
    Public ReadOnly Property SaveFile As ICommand
        Get
            Return _saveFile
        End Get
    End Property

    Private ReadOnly _openFile As New OpenFileCommand(Me)
    Public ReadOnly Property OpenFile As ICommand
        Get
            Return _openFile
        End Get
    End Property

    Private _regexPattern As String
    Public Property RegexPattern() As String
        Get
            Return _regexPattern
        End Get
        Set(ByVal value As String)
            _regexPattern = value
            OnPropertyChanged(New PropertyChangedEventArgs("RegexPattern"))
        End Set
    End Property

    Private _isCompiled As Boolean
    Public Property IsCompiled() As Boolean
        Get
            Return _isCompiled
        End Get
        Set(ByVal value As Boolean)
            _isCompiled = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsCompiled"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isCultureInvariant As Boolean
    Public Property IsCultureInvariant() As Boolean
        Get
            Return _isCultureInvariant
        End Get
        Set(ByVal value As Boolean)
            _isCultureInvariant = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsCultureInvariant"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isEcmaScript As Boolean
    Public Property IsEcmaScript() As Boolean
        Get
            Return _isEcmaScript
        End Get
        Set(ByVal value As Boolean)
            _isEcmaScript = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsEcmaScript"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isExplicitCapture As Boolean
    Public Property IsExplicitCapture() As Boolean
        Get
            Return _isExplicitCapture
        End Get
        Set(ByVal value As Boolean)
            _isExplicitCapture = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsExplicitCapture"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isIgnoreCase As Boolean
    Public Property IsIgnoreCase() As Boolean
        Get
            Return _isIgnoreCase
        End Get
        Set(ByVal value As Boolean)
            _isIgnoreCase = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsIgnoreCase"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isIgnorePatternWhitespace As Boolean
    Public Property IsIgnorePatternWhitespace() As Boolean
        Get
            Return _isIgnorePatternWhitespace
        End Get
        Set(ByVal value As Boolean)
            _isIgnorePatternWhitespace = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsIgnorePatternWhitespace"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isMultiline As Boolean
    Public Property IsMultiline() As Boolean
        Get
            Return _isMultiline
        End Get
        Set(ByVal value As Boolean)
            _isMultiline = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsMultiline"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isRightToLeft As Boolean
    Public Property IsRightToLeft() As Boolean
        Get
            Return _isRightToLeft
        End Get
        Set(ByVal value As Boolean)
            _isRightToLeft = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsRightToLeft"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Private _isSingleline As Boolean
    Public Property IsSingleline() As Boolean
        Get
            Return _isSingleline
        End Get
        Set(ByVal value As Boolean)
            _isSingleline = value
            OnPropertyChanged(New PropertyChangedEventArgs("IsSingleline"))
            OnPropertyChanged(New PropertyChangedEventArgs("RegexOptions"))
        End Set
    End Property

    Public Property RegexOptions As RegexOptions
        Get
            Return RegexOptions.None Or
                If(Me.IsCompiled, RegexOptions.Compiled, RegexOptions.None) Or
                If(Me.IsCultureInvariant, RegexOptions.CultureInvariant, RegexOptions.None) Or
                If(Me.IsEcmaScript, RegexOptions.ECMAScript, RegexOptions.None) Or
                If(Me.IsExplicitCapture, RegexOptions.ExplicitCapture, RegexOptions.None) Or
                If(Me.IsIgnoreCase, RegexOptions.IgnoreCase, RegexOptions.None) Or
                If(Me.IsIgnorePatternWhitespace, RegexOptions.IgnorePatternWhitespace, RegexOptions.None) Or
                If(Me.IsMultiline, RegexOptions.Multiline, RegexOptions.None) Or
                If(Me.IsRightToLeft, RegexOptions.RightToLeft, RegexOptions.None) Or
                If(Me.IsSingleline, RegexOptions.Singleline, RegexOptions.None)
        End Get
        Set(ByVal value As RegexOptions)
            Me.IsCompiled = value And RegexOptions.Compiled
            Me.IsCultureInvariant = value And RegexOptions.CultureInvariant
            Me.IsEcmaScript = value And RegexOptions.ECMAScript
            Me.IsExplicitCapture = value And RegexOptions.ExplicitCapture
            Me.IsIgnoreCase = value And RegexOptions.IgnoreCase
            Me.IsIgnorePatternWhitespace = value And RegexOptions.IgnorePatternWhitespace
            Me.IsMultiline = value And RegexOptions.Multiline
            Me.IsRightToLeft = value And RegexOptions.RightToLeft
            Me.IsSingleline = value And RegexOptions.Singleline
        End Set
    End Property

    Private _selectedSearchMode As RegexSearchMode
    Public Property SelectedSearchMode() As RegexSearchMode
        Get
            Return _selectedSearchMode
        End Get
        Set(ByVal value As RegexSearchMode)
            _selectedSearchMode = value
            OnPropertyChanged(New PropertyChangedEventArgs("SelectedSearchMode"))
        End Set
    End Property

    Private _sampleInput As String
    Public Property SampleInput() As String
        Get
            Return _sampleInput
        End Get
        Set(ByVal value As String)
            _sampleInput = value
            OnPropertyChanged(New PropertyChangedEventArgs("SampleInput"))
        End Set
    End Property

    Private _findInFilesFolder As String
    Public Property FindInFilesFolder() As String
        Get
            Return _findInFilesFolder
        End Get
        Set(ByVal value As String)
            _findInFilesFolder = value
            OnPropertyChanged(New PropertyChangedEventArgs("FindInFilesFolder"))
        End Set
    End Property

    Private _searchInSubFolders As Boolean
    Public Property SearchInSubFolders() As Boolean
        Get
            Return _searchInSubFolders
        End Get
        Set(ByVal value As Boolean)
            _searchInSubFolders = value
            OnPropertyChanged(New PropertyChangedEventArgs("SearchInSubFolders"))
        End Set
    End Property

    Private _fileNameFilter As String = ""
    Public Property FileNameFilter() As String
        Get
            Return _fileNameFilter
        End Get
        Set(ByVal value As String)
            _fileNameFilter = value
            OnPropertyChanged(New PropertyChangedEventArgs("FileNameFilter"))
        End Set
    End Property

    Private _fileNameFilterResults As IEnumerable(Of String)
    Public Property FileNameFilterResults() As IEnumerable(Of String)
        Get
            Return _fileNameFilterResults
        End Get
        Private Set(ByVal value As IEnumerable(Of String))
            _fileNameFilterResults = value
            OnPropertyChanged(New PropertyChangedEventArgs("FileNameFilterResults"))
        End Set
    End Property

#End Region

#Region "Constructors"

#End Region

#Region "Methods"
    Private Sub LoadFileNameFilterResults()
        If IO.Directory.Exists(Me.FindInFilesFolder) Then
            Dim l_files As String()

            Try
                l_files = IO.Directory.GetFiles(Me.FindInFilesFolder, "*", If(Me.SearchInSubFolders, IO.SearchOption.AllDirectories, IO.SearchOption.TopDirectoryOnly))
            Catch ex As System.UnauthorizedAccessException
                l_files = New String() {ex.Message}
            End Try

            Try
                Me.FileNameFilterResults =
                    From f In l_files
                    Where Regex.IsMatch(f, If(Me.FileNameFilter, ""))
                    Select f.Replace(Me.FindInFilesFolder, "")
            Catch ex As ArgumentException
                Me.FileNameFilterResults = New String() {ex.Message}
            End Try
        Else
            Me.FileNameFilterResults = New String() {"Directory not valid or not recognized."}
        End If
    End Sub
#End Region

#Region "Event Raiser Methods"
    Protected Overloads Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
        RaiseEvent PropertyChanged(sender:=Me, e:=e)
    End Sub
#End Region

#Region "Event Handlers"
    Private Sub MainWindow_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Handles Me.PropertyChanged

        Select Case e.PropertyName
            Case "FindInFilesFolder", "SearchInSubFolders", "FileNameFilter"
                LoadFileNameFilterResults()

        End Select

    End Sub
#End Region

End Class



#Region "Command Classes"
Partial Class MainWindow


#Region "ExecuteRegExCommand"
    Private Class ExecuteRegExCommand
        Implements ICommand

        Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged

        Private ReadOnly _parent As MainWindow

        Public Sub New(ByVal parent As MainWindow)
            _parent = parent
        End Sub

        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
            Return True
        End Function

        Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
            Select Case _parent.SelectedSearchMode

                Case RegexSearchMode.SampleInput
                    Dim l_resultsWindow As New SampleInputResultsWindow()
                    l_resultsWindow.RegexPattern = _parent.RegexPattern
                    l_resultsWindow.SampleInput = _parent.SampleInput
                    l_resultsWindow.RegexOptions = _parent.RegexOptions
                    l_resultsWindow.ShowDialog()

                Case RegexSearchMode.FindInFiles
                    Dim l_resultsWindow As New FindInFilesResultsWindow()
                    l_resultsWindow.RegexPattern = _parent.RegexPattern
                    l_resultsWindow.RegexOptions = _parent.RegexOptions
                    l_resultsWindow.FindInFilesFolder = _parent.FindInFilesFolder
                    l_resultsWindow.FileNameFilter = _parent.FileNameFilter
                    l_resultsWindow.SearchInSubFolders = _parent.SearchInSubFolders
                    l_resultsWindow.ShowDialog()

            End Select
        End Sub
    End Class
#End Region


#Region "FindInFilesBrowseFoldersCommand"
    Private Class FindInFilesBrowseFoldersCommand
        Implements ICommand

        Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged

        Private ReadOnly _parent As MainWindow

        Public Sub New(ByVal parent As MainWindow)
            _parent = parent
        End Sub

        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
            Return True
        End Function

        Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
            Dim l_dialog = New System.Windows.Forms.FolderBrowserDialog()
            If _
                Not String.IsNullOrWhiteSpace(_parent.FindInFilesFolder) AndAlso
                Directory.Exists(_parent.FindInFilesFolder) _
            Then
                l_dialog.SelectedPath = _parent.FindInFilesFolder
            End If

            l_dialog.Description = "Select Folder for Searching"
            l_dialog.ShowNewFolderButton = False
            If l_dialog.ShowDialog() = Forms.DialogResult.OK Then
                _parent.FindInFilesFolder = l_dialog.SelectedPath
            End If
        End Sub
    End Class
#End Region


#Region "SaveFileCommand"
    Private Class SaveFileCommand
        Implements ICommand

        Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged

        Private ReadOnly _parent As MainWindow

        Public Sub New(ByVal parent As MainWindow)
            _parent = parent
        End Sub

        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
            Return True
        End Function

        Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
            Dim l_dialog = New Microsoft.Win32.SaveFileDialog()
            l_dialog.AddExtension = True
            l_dialog.CheckPathExists = True
            l_dialog.ValidateNames = True
            l_dialog.DefaultExt = ".regex"
            l_dialog.Filter = "Regex Files (*.regex)|*.regex"
            l_dialog.Title = "Save Regex File"
            If l_dialog.ShowDialog() Then
                Dim l_stream = File.Open(l_dialog.FileName, FileMode.Create, FileAccess.Write, FileShare.None)
                Dim l_writer As New StreamWriter(l_stream)

                Dim l_regexDocument =
                    <regex>
                        <pattern>
                            <%= _parent.RegexPattern %>
                        </pattern>
                        <options>
                            <%= _parent.RegexOptions %>
                        </options>
                        <mode>
                            <%= _parent.SelectedSearchMode %>
                        </mode>
                        <sampleInput>
                            <%= _parent.SampleInput %>
                        </sampleInput>
                        <folder>
                            <%= _parent.FindInFilesFolder %>
                        </folder>
                        <searchInSubFolders>
                            <%= _parent.SearchInSubFolders %>
                        </searchInSubFolders>
                        <fileNameFilter>
                            <%= _parent.FileNameFilter %>
                        </fileNameFilter>
                    </regex>

                l_writer.Write(l_regexDocument.ToString())
                l_writer.Flush()
                l_stream.Close()
            End If
        End Sub

        Private Function EscapeXml(ByVal input As String) As String
            If Not String.IsNullOrEmpty(input) Then
                input = Regex.Replace(input, "[&]", "&amp;")
                input = Regex.Replace(input, "[<]", "&lt;")
                input = Regex.Replace(input, "[>]", "&gt;")
            End If

            Return input
        End Function
    End Class
#End Region


#Region "OpenFileCommand"
    Private Class OpenFileCommand
        Implements ICommand

        Public Event CanExecuteChanged(ByVal sender As Object, ByVal e As System.EventArgs) Implements System.Windows.Input.ICommand.CanExecuteChanged

        Private ReadOnly _parent As MainWindow

        Public Sub New(ByVal parent As MainWindow)
            _parent = parent
        End Sub

        Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
            Return True
        End Function

        Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
            Dim l_dialog = New Microsoft.Win32.OpenFileDialog()
            l_dialog.AddExtension = True
            l_dialog.CheckFileExists = True
            l_dialog.CheckPathExists = True
            l_dialog.ValidateNames = True
            l_dialog.DefaultExt = ".regex"
            l_dialog.Filter = "Regex Files (*.regex)|*.regex"
            l_dialog.Title = "Save Regex File"
            If l_dialog.ShowDialog() Then
                Dim l_stream = File.Open(l_dialog.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)
                Dim l_reader As New StreamReader(l_stream)

                Dim l_content = l_reader.ReadToEnd()

                l_stream.Close()

                Dim l_regexDocument = XDocument.Parse(l_content)

                _parent.RegexPattern =
                    l_regexDocument...<pattern>.Value
                _parent.RegexOptions =
                    [Enum].Parse(GetType(RegexOptions), l_regexDocument...<options>.Value)
                _parent.SelectedSearchMode =
                    [Enum].Parse(GetType(RegexSearchMode), l_regexDocument...<mode>.Value)
                _parent.SampleInput =
                    l_regexDocument...<sampleInput>.Value
                _parent.FindInFilesFolder =
                    l_regexDocument...<folder>.Value
                _parent.SearchInSubFolders =
                    Boolean.Parse(l_regexDocument...<searchInSubFolders>.Value)
                _parent.FileNameFilter =
                    l_regexDocument...<fileNameFilter>.Value

            End If
        End Sub
    End Class
#End Region


End Class
#End Region
